﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.IO;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
using System.Xml;

namespace PSE.Tools.ProjectDependencyDiscovery
{
	class XmlManager
    {
		/// <summary>
		/// Variaveis globais
		/// Representam as listas que serao preenchidas, principalmente com as referencias entre projetos
		/// a Variavel RefsPorDLL representa as referencias por DLL
		/// a Variavel RefsPorProjeto representa as referencias por Projeto
		/// a Variavel RefsGeral representa a uniao das referencias por DLL e Projeto
		/// a Variavel CompileCS representa os arquivos CS que contem as classes
		/// </summary>
        private static XmlDocument DocumentoXML;
        //private static BindingList<string> RefsPorDLL;
		//private static BindingList<string> CompileCS;
        //private static BindingList<string> RefsPorProjeto;
        //private static BindingList<string> RefsGeral;

		/// <summary>
		/// Construtor
		/// Inicializa as variaveis globais
		/// </summary>
        public XmlManager()
        {
            DocumentoXML = new XmlDocument();
            //RefsPorDLL = new BindingList<string>();
            //RefsPorProjeto = new BindingList<string>();
            //RefsGeral = new BindingList<string>();
			//CompileCS = new BindingList<string>();
        }

		/// <summary>
		/// Este metodo lista todas as referencias de um Projeto, dado o endereço do projeto.
		/// A parte deste metodo que verifica referencias por projeto esta comentada, pois neste momento estamos 
		/// interessados apenas em referencias por DLL, que indicam referencias que precisam de fato serem compiladas antes
		/// do Projeto em questao.
		/// Alem disso, o metodo considera um padrao de nomenclatura para o Projeto Sinacor+:
		/// toda DLL de servico deve conter a string "Sinacor.Servicos."
		/// e este metodo retira esta string dos nomes encontados.
		/// </summary>
		/// <param name="AddressProject"></param>
		/// <returns></returns>
        /// 
        public List<string> ListarDependenciaProjeto(string projectFullPath) 
        {
            List<string> dependencies = new List<string>();

            List<string> projectReferences = this.LerReferenciasProjeto(projectFullPath);
            List<string> libraryReferences = this.LerReferencias(projectFullPath);

            foreach (string Referencias in libraryReferences) 
            {
				string projeto = string.Empty;

                // Obtem apenas o nome do assembly e concatena com .csproj para obeter o nome do projeto
                int index_of_Version = Referencias.IndexOf(", Version"); //incluido - esertorio/emorais - 200808112125
                if (index_of_Version >= 0) //incluido - esertorio/emorais - 200808112125
                    //projeto = Referencias.Substring(0, Referencias.IndexOf(", Version")) + ".csproj";
                    projeto = Referencias.Substring(0, Referencias.IndexOf(", Version")) + ".dll";
                else
                    //projeto = Referencias + ".csproj"; //incluido - esertorio/emorais - 200808112125
                    projeto = Referencias + ".dll";
                dependencies.Add(projeto);
            }

            foreach (string Referencias in projectReferences)
            {
                string projeto = string.Empty;
                projeto = Referencias.Split('\\')[Referencias.Split('\\').Length - 1];
                dependencies.Add(projeto);
            }

            return dependencies;
        }

        private List<string> ListarDependenciaReferencias(string projectFullPath)
        {
            List<string> dependencies = new List<string>();

            return null;
        }


		/// <summary>
		/// Este metodo buscar as tags "Reference" e "ProjectReference" nos arquivo csproj para encontrar 
		/// as referencias por DLL e Projeto respectivamente.
		/// </summary>
		/// <param name="AddressProject"></param>
        private List<string> LerReferenciasProjeto(string projectFullPath)
        {
            List<string> projectReferences = new List<string>();

            DocumentoXML.Load(projectFullPath);
            XmlNodeList ItemGroup = DocumentoXML.GetElementsByTagName("ItemGroup");
            
            foreach (XmlNode No in ItemGroup)
            {
                foreach (XmlNode referencia in No.ChildNodes)
                {
                    // Captura qualquer projeto que tenha sido referenciado.
                    if (referencia.Name == "ProjectReference")
                    {
                        XmlAttribute Include = referencia.Attributes[0];
                        projectReferences.Add(Include.InnerText);
                    }
                }
            }

            return projectReferences;
        }

        private List<string> LerReferencias(string projectFullPath)
        {
            List<string> references = new List<string>();

            DocumentoXML.Load(projectFullPath);
            XmlNodeList ItemGroup = DocumentoXML.GetElementsByTagName("ItemGroup");

            foreach (XmlNode No in ItemGroup)
            {
                foreach (XmlNode referencia in No.ChildNodes)
                {
                    // Captura apenas as referências a dlls do Sinacor (Sinacor, Bovespa, Bmf ou FileHelpers) 
                    if (referencia.Name == "Reference")
                    {
                        XmlAttribute Include = referencia.Attributes[0];
                        references.Add(Include.InnerText);
                    }
                }
            }

            return references;
        }

        /// <summary>
        /// Este metodo busca a tag "Include" para encontrar includes de cada Projeto.
        /// </summary>
        /// <param name="projectFullPath"></param>
        /// <returns></returns>
        public List<string> ListarIncludesProjeto(string projectFullPath)
        {
            List<string> includes = new List<string>();

            DocumentoXML.Load(projectFullPath);

            XmlNodeList ItemGroup = DocumentoXML.GetElementsByTagName("ItemGroup");

            foreach (XmlNode node in ItemGroup)
            {
                foreach (XmlNode compile in node.ChildNodes)
                {
                    if (compile.Name == "Content")
                    {
                        XmlAttribute Include = compile.Attributes[0];
                        string[] splitAd = projectFullPath.Split('\\');
                        int len = projectFullPath.Split('\\').Length;
                        string s = projectFullPath.Replace(splitAd[len - 1], "");
                        includes.Add(s + Include.InnerText);
                    }
                }
            }

            return includes;
        }

		/// <summary>
		/// Este metodo busca a tag "Compile" para encontrar as classes de cada Projeto.
		/// Cada arquivo CS corresponde a implementacao de uma classe.
		/// </summary>
		/// <param name="AddressProject"></param>
        public List<string> ListarClassesProjeto(string projectFullPath)
		{
            List<string> classes = new List<string>();

            DocumentoXML.Load(projectFullPath);

			XmlNodeList ItemGroup = DocumentoXML.GetElementsByTagName("ItemGroup");

			foreach (XmlNode node in ItemGroup)
			{
                foreach (XmlNode compile in node.ChildNodes)
				{
					if (compile.Name == "Compile")
					{
						XmlAttribute Include = compile.Attributes[0];
                        string[] splitAd = projectFullPath.Split('\\');
                        int len = projectFullPath.Split('\\').Length;
                        string s = projectFullPath.Replace(splitAd[len - 1], "");
                        classes.Add(s + Include.InnerText);
					}
				}
			}

            return classes;
		}

	}
}